# coding:utf-8
import os
import sys
import logging
import argparse
import re
import json
import time
import random
import string
from pathlib import Path
import base64
from enum import Enum, unique
import configparser
import requests
from flask import Flask
from flask import request
from flask import Response
from flask import jsonify, make_response
from flask_cors import CORS
from ais.utils import cfg, setup_logger, load_cfg_file
from app.ais_app import AisApp
from ais.surgery import surgery_info
from Multiclass_Object_Classification.MainFile import pred
# print(os.getcwd())
# sys.path.append(os.getcwd())
# docker data root and host root
ais_version = '1.2.6'
docker_data_root = '/usr/local/data/DR/AIS'
host_data_root = '/home/cao/data/dicom/AIS'
deploy_config_file = '/home/cao/PycharmProjects/AIS_Algorithm/experiment/app/ais_seg_hrnet_w18_landmark_spinnet_res34_v1.0.0.yml'
image_url_prefix = 'http://192.168.30.30:8088/file/download/'

server_name = 'DR_AIS_DET'
debug_flag = True
logger = None
ais_app: AisApp = None
port_number = 5081


def parse_args():
    parser = argparse.ArgumentParser(description="AIS DR Measurement Inference Service!")
    parser.add_argument('--ini',
                        type=str,
                        help='ini config file',
                        default='web_server.ini')
    return parser.parse_args()


def parse_config_ini(ini_file:Path):
    if Path(ini_file).exists():
        config = configparser.ConfigParser()
        config.read(str(ini_file))
        global server_name, debug_flag, docker_data_root, host_data_root, deploy_config_file, image_url_prefix, port_number
        server_name = config['DEFAULT']['server_name']
        debug_flag = config['DEFAULT'].getboolean('debug_flag')
        port_number = int(config['DEFAULT']['port_number'])
        docker_data_root = config['docker']['docker_data_root']
        host_data_root = config['docker']['host_data_root']
        deploy_config_file = config['ais_model']['deploy_config_file']
        image_url_prefix = config['backend_service']['image_url_prefix']
    else:
        print("ini_file: {} not found!!!".format(str(ini_file)))
        sys.exit(1)

@unique
class HTTPResCode(Enum):
    Failed = 0
    Interface_success = 1000
    Interface_auth_failed = 1001
    License_expired = 1002
    Miss_parameter = 1003
    Serices_uncompleted = 1004
    Image_modality = 1005
    Serices_empty = 1006

@unique
class ScannerType(Enum):
    X_ray = 1
    CT=2

@unique
class UploadStatus(Enum):
    Faile = 0
    Success = 1

@unique
class StoreType(Enum):
    Local = 0
    Base64 = 1
    URL = 2

@unique
class DRDirection(Enum):
    AP = 0
    LAT = 1
    Lbend = 2
    Rbend = 3
    Unknown = 4

@unique
class ImageFileType(Enum):
    JPG = 0
    DICOM = 1


def is_docker():
    path = "/proc/" + str(os.getpid()) + "/cgroup"
    if not os.path.isfile(path): return False
    with open(path) as f:
        for line in f:
            if re.match("\d+:[\w=]+:/docker(-[ce]e)?/\w+", line):
                return True
    return False


def check_save_dir(seriesno)->Path:
    if is_docker():
        # convert docker file path
        save_dir = docker_data_root
    else:
        save_dir = host_data_root

    save_dir = Path(save_dir)
    if not save_dir.exists():
        os.makedirs(str(save_dir))

    save_dir = Path(save_dir).joinpath(seriesno)
    if not save_dir.exists():
        save_dir.mkdir()
    return save_dir


def parsing_ais_data(seriesno, ais_data_list):
    # image_dict = {'ap': ap_file,
    #               'lat': lat_file,
    #               'lbend': lbend_file,
    #               'rbend': rbend_file}
    if ais_data_list:
        save_dir = check_save_dir(seriesno)
        ais_file_dict = {}
        for i, ais_image in enumerate(ais_data_list):
            orientation = str(ais_image.get('orientation', DRDirection.Unknown.name)).lower()
            if ais_image['storeType'] == StoreType.Local.name:
                ais_file_dict[orientation] =  str(ais_image.get('content', ''))
            elif ais_image['storeType'] == StoreType.Base64.name:
                image_content = ais_image.get('content', '')
                image_bs64_str = image_content.encode('utf-8')
                imgdata = base64.b64decode(image_bs64_str)
                filetype = ais_image.get('fileType', ImageFileType.JPG.name)
                # image_sopNo = ''.join(random.sample(string.ascii_letters + string.digits, 10))
                image_sopNo = orientation
                if filetype == 'JPG':
                    save_name = save_dir.joinpath(image_sopNo + '.jpg')
                elif filetype == 'DICOM':
                    save_name = save_dir.joinpath(image_sopNo + '.dcm')
                with open(str(save_name), "wb") as f:
                    f.write(imgdata)
                ais_file_dict[orientation] = str(save_name)
            elif ais_image['storeType'] == StoreType.URL.name:
                image_content = ais_image.get('content', '')
                image_content = image_url_prefix+str(image_content)
                res = requests.get(str(image_content))
                image_sopNo = orientation
                filetype = ais_image.get('fileType', ImageFileType.JPG.name)
                if filetype == 'JPG':
                    save_name = save_dir.joinpath(image_sopNo + '.jpg')
                elif filetype == 'DICOM':
                    save_name = save_dir.joinpath(image_sopNo + '.dcm')
                with open(str(save_name), "wb") as f:
                    f.write(res.content)
                ais_file_dict[orientation] = str(save_name)
        return ais_file_dict, save_dir


# new flask app
app = Flask(server_name)
app.config['JSON_AS_ASCII'] = False


@app.route('/', methods=['GET', 'POST'])
def version():
    return jsonify({str(server_name) + " version": ais_version})


@app.route('/api/v1/ais/demo-det', methods=['GET', 'POST'])
def test_demo():
    """
    本地测试ais检测
    :return:
    """
    case_dir = Path('image/ais_demo')
    ap_file = case_dir.joinpath('ap.jpg')
    lat_file = case_dir.joinpath('lat.jpg')
    lbend_file = case_dir.joinpath('lbend.jpg')
    rbend_file = case_dir.joinpath('rbend.jpg')
    ais_info = {}
    if ap_file.exists() and lat_file.exists() and lbend_file.exists() and rbend_file.exists():
        image_dict = {'ap': ap_file,
                      'lat': lat_file,
                      'lbend': lbend_file,
                      'rbend': rbend_file}
        ais_info = ais_app.lenke_det(image_dict)
        logger.info("Testing api: '/api/v1/ais/demo-det' case_dir: {} successed!".format(str(case_dir)))
        return jsonify(ais_info)
    logger.info("Testing api: '/api/v1/ais/demo-det' case_dir: {} failed!".format(str(case_dir)))
    return jsonify(ais_info)


@app.route('/api/v1/ais/lenke-det',methods=['GET', 'POST'])
def dr_ais_cobb_det():
    res: dict = json.loads(request.data)
    scannerType = res.get('scannerType', 1)
    seriesNo = res.get('seriesNo', '')
    status = res.get('status', 0)
    ais_images = res.get('data', [])

    try:
        results = {}
        results['scannerType'] = 1
        results['seriesNo'] = seriesNo
        results['aisInfo'] = {}
        results['code'] = HTTPResCode.Failed.value
        results['msg'] = ''

        if status != UploadStatus.Success.value:
            results['code'] = HTTPResCode.Serices_uncompleted.value
            return jsonify(results)

        if scannerType != ScannerType.X_ray.value:
            results['code'] = HTTPResCode.Image_modality.value
            return jsonify(results)

        if not ais_images:
            results['code'] = HTTPResCode.Serices_empty.value
            return jsonify(results)

        # 1.create ais images
        save_dir = None
        ais_file_dict, save_dir = parsing_ais_data(seriesNo, ais_images)

        # 2.ais det
        logger.info("'/api/v1/ais/lenke-det' processing.... ais_file_dict: {},  dir: {}".format(str(ais_file_dict), str(save_dir)))
        ais_info = ais_app.lenke_det(ais_file_dict)
        results['aisInfo'] = ais_info

        results['code'] = HTTPResCode.Interface_success.value
        logger.info("'/api/v1/ais/lenke-det' successed! seriesNo: {}, save_dir: {}".format(str(seriesNo), str(save_dir)))
        return jsonify(results)
    except Exception as e:
        logger.error("'/api/v1/ais/lenke-det' failed! seriesNo: {}, save_dir: {}, error:{}".format(str(seriesNo), str(save_dir), e))
        return jsonify(results)


@app.route('/api/v1/ais/lenke-surgery',methods=['GET', 'POST'])
def dr_lenke_surgery_det():
    """
    lenke 分析手术建议模板
    :return:
    """
    res: dict = json.loads(request.data)
    scannerType = res.get('scannerType', 1)
    seriesNo = res.get('seriesNo', '')
    lenke_info = res.get('data', {})

    try:
        results = {}
        results['scannerType'] = 1
        results['seriesNo'] = seriesNo
        results['aisInfo'] = {}
        results['code'] = HTTPResCode.Failed.value
        results['msg'] = ''

        if scannerType != ScannerType.X_ray.value:
            results['code'] = HTTPResCode.Image_modality.value
            return jsonify(results)

        results['surgInfo'] = ''
        if lenke_info:
            if 'curve_type' in lenke_info and 'ls_modifier' in lenke_info and 'ts_modifier' in lenke_info:
                curve_type = lenke_info.get('curve_type', 1)
                ls_modifier = lenke_info.get('ls_modifier', 'A')
                ts_modifier = lenke_info.get('ts_modifier', '+')
                results['surgInfo'] = surgery_info(int(curve_type), ls_modifier)

        results['code'] = HTTPResCode.Interface_success.value
        logger.info("'/api/v1/ais/lenke-surgery' successed: {}: {}".format(str(seriesNo), results['surgInfo']))
        return jsonify(results)
    except Exception as e:
        logger.error("'/api/v1/ais/lenke-surgery' failed: {}".format(e))
        return jsonify(results)


@app.route('/api/v1/ais/image_class', methods=['POST'])
def dr_ais_image_class():
    upload_file = request.files['file']
    file_name = upload_file.filename
    try:
        result = {}
        result['imageClass'] = None
        result['code'] = HTTPResCode.Failed.value
        result['msg'] = ''

        image_dir = os.path.join(os.getcwd(), 'Multiclass_Object_Classification/download/')
        upload_file.save(Path(image_dir + file_name))

        # image class
        image_class = pred(image_dir + file_name)
        print(image_class)
        if image_class == 0:
            result['imageClass'] = 'AP'
        elif image_class == 1:
            result['imageClass'] = 'LAT'
        elif image_class == 2:
            result['imageClass'] = 'LBend'
        elif image_class == 3:
            result['imageClass'] = 'RBend'
        result['code'] = HTTPResCode.Interface_success.value
        os.remove(Path(image_dir + file_name))
        return jsonify(result)
    except Exception as e:
        import traceback
        print(traceback.format_exc())
        return jsonify(result)


def main():
    # parse ini file
    args = parse_args()
    parse_config_ini(args.ini)

    # load model deploy_config_file
    load_cfg_file(deploy_config_file)
    logger_file = Path(cfg.LOG.DIR).joinpath("AIS-WebServer" + time.strftime("--%Y-%m-%d-%H-%M-%S", time.localtime()))
    if not Path(logger_file.parent).exists():
        os.makedirs(str(logger_file.parent))

    global logger, ais_app
    logger = setup_logger(Path(__file__).name, level=logging.INFO, filepath=logger_file)

    logger.info("start init ais_app...")
    ais_app = AisApp(logger_file)
    ais_app.init()
    logger.info("init ais_app successed!")

    CORS(app, supports_credentials=True)
    if debug_flag:
        app.run(host='0.0.0.0', use_reloader=False, port=port_number, debug=True, processes=1)
    else:
        app.run(host='0.0.0.0', use_reloader=True, port=port_number)


def deploy():
    # parse ini file
    args = parse_args()
    parse_config_ini(args.ini)

    # load model deploy_config_file
    load_cfg_file(deploy_config_file)
    logger_file = Path(cfg.LOG.DIR).joinpath("AIS-WebServer" + time.strftime("--%Y-%m-%d-%H-%M-%S", time.localtime()))
    if not Path(logger_file.parent).exists():
        os.makedirs(str(logger_file.parent))

    global logger, ais_app
    logger = setup_logger(Path(__file__).name, level=logging.INFO, filepath=logger_file)

    logger.info("start init ais_app...")
    ais_app = AisApp(logger_file)
    ais_app.init()
    logger.info("init ais_app successed!")

    CORS(app, supports_credentials=True)


if __name__ == '__main__':
    main()
else:
    deploy()


